package com.zjdiepu.www.common.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 反射
 * 
 * @ClassName: ReflectUtil
 * @Description:反射类
 * @author xiongxiaotun@126.com
 * @date 2015年5月22日 上午9:16:34
 */
public class ReflectUtil {
	/**
	 * 
	 * 查找所有声明的方法
	 * 
	 * @param clazz
	 * 
	 * @return
	 */
	private static Method[] getDeclaredMethods(Class<?> clazz) {
		Method[] result = clazz.getDeclaredMethods();
		return result;
	}

	/**
	 * 
	 * 匹配查询clazz中的方法
	 * @param clazz
	 * @param name
	 * @param paramTypes
	 * @return
	 */
	public static Method findMethod(Class<?> clazz, String name,
			Class<?>... paramTypes) {
		notNull(clazz, "参数类型clazz不能为空");
		notNull(name, "参数方法名name不能为空");
		Class<?> searchType = clazz;
		while (searchType != null) {
			Method[] methods = (searchType.isInterface() ? searchType
					.getMethods() : getDeclaredMethods(searchType));
			for (Method method : methods) {
				if (name.equals(method.getName())
						&& (paramTypes == null || Arrays.equals(paramTypes,
								method.getParameterTypes()))) {
					return method;
				}
			}
			searchType = searchType.getSuperclass();
		}
		return null;
	}

	/**
	 * null对象异常
	 * @param object
	 * @param message
	 */
	public static void notNull(Object object, String message) {
		if (object == null) {
			throw new IllegalArgumentException(message);
		}
	}

	/**
	 * 
	 * 获取泛型类型参数
	 * @param parameterType
	 * @return
	 */
	public static Type[] parameterTypeOfGengricType(Type gengricType) {
		if (gengricType == null)
			return null;
		if (!isParameterizedType(gengricType))
			return null;
		ParameterizedType parameterizedType = (ParameterizedType) gengricType;
		Type[] types = parameterizedType.getActualTypeArguments();
		return types;
	}

	/**
	 * 
	 * 是不是泛型类型
	 * @param parameterType
	 * @return
	 */
	public static boolean isParameterizedType(Type type) {
		if (type == null)
			return false;
		return ParameterizedType.class.isAssignableFrom(type.getClass());
	}

	/**
	 * 根据参数对象获取参数接口类型
	 * @param obj
	 * @return
	 */
	public static String getTypeName(Object obj) {
		String typeName = "";
		if (obj instanceof List) {
			typeName = "java.util.List";
		} else if (obj instanceof Set) {
			typeName = "java.util.Set";
		} else if (obj instanceof Map) {
			typeName = "java.util.Map";
		} else {
			typeName = obj.getClass().getName();
		}
		return typeName;
	}

	/**
	 * 反射得到类字段值.
	 * @param name the name
	 * @param obj the obj
	 * @return the value
	 */
	public static Object getValue(String name, Object obj) {
		Class<?> cl = obj.getClass();
		try {
			Method method = cl.getMethod(StringUtil.getFieldMethod(name));
			return method.invoke(obj);
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * Gets the field.
	 * @param name the name
	 * @param obj the obj
	 * @return the field
	 */
	public static Field getField(String name, Object obj) {
		Class<?> cl = obj.getClass();
		Field field = null;
		try {
			field = cl.getDeclaredField(name);
			field.setAccessible(true);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}
		return field;
	}

	/**
	 * Gets the fields.
	 * @param clzzz the obj
	 * @return the fields
	 */
	public static Map<String, Field> getFields(Class<?> clzzz) {
		Map<String, Field> map = new HashMap<String, Field>();
		Field[] fields = clzzz.getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			map.put(field.getName(), field);
		}
		if (clzzz.getSuperclass() != Object.class) {
			map.putAll(getFields(clzzz.getSuperclass()));
		}
		return map;
	}

	/**
	 * 实体转化.
	 * @param <T> the generic type
	 * @param name the name
	 * @param t the t
	 * @param obj the obj
	 * @return the t
	 */
	public static <T> T converObject(String name, T t, Object obj) {
		Class<?> cl = t.getClass();
		try {
			Method method = null;
			try {
				method = cl.getMethod(StringUtil.setFieldMethod(name),
						getFields(cl).get(name).getType());
			} catch (Exception e) {// 本身的私有方法
				method = cl.getDeclaredMethod(StringUtil.setFieldMethod(name),
						getFields(cl).get(name).getType());
			}
			method.invoke(t, obj);
			return t;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return t;
	}
}